﻿using Engine;
using System;
using System.Collections.Generic;

namespace Game
{
    /// <summary>
    /// 圆锥区域
    /// </summary>
    public class ConeArea
    {
        public int Radius;
        public int Height;
        public Point3 Center;
        public CoordDirection Coord;
        public Point3 MaxPoint;
        public Point3 MinPoint;
        public Point3 Current;
        public int LengthX;
        public int LengthY;
        public int LengthZ;

        public ConeArea(int r, int h, Point3 c, CoordDirection coord)
        {
            Radius = r;
            Height = h;
            Center = c;
            Coord = coord;
            Current = Center;
            switch (Coord)
            {
                case CoordDirection.PX:
                    {
                        MinPoint = Center - new Point3(0, Radius, Radius);
                        MaxPoint = Center + new Point3(Height, Radius, Radius);
                    }
                    break;
                case CoordDirection.PY:
                    {
                        MinPoint = Center - new Point3(Radius, 0, Radius);
                        MaxPoint = Center + new Point3(Radius, Height, Radius);
                    }
                    break;
                case CoordDirection.PZ:
                    {
                        MinPoint = Center - new Point3(Radius, Radius, 0);
                        MaxPoint = Center + new Point3(Radius, Radius, Height);
                    }
                    break;
                case CoordDirection.NX:
                    {
                        MinPoint = Center - new Point3(Height, Radius, Radius);
                        MaxPoint = Center + new Point3(0, Radius, Radius);
                    }
                    break;
                case CoordDirection.NY:
                    {
                        MinPoint = Center - new Point3(Radius, Height, Radius);
                        MaxPoint = Center + new Point3(Radius, 0, Radius);
                    }
                    break;
                case CoordDirection.NZ:
                    {
                        MinPoint = Center - new Point3(Radius, Radius, Height);
                        MaxPoint = Center + new Point3(Radius, Radius, 0);
                    }
                    break;
            }
            LengthX = MaxPoint.X - MinPoint.X + 1;
            LengthY = MaxPoint.Y - MinPoint.Y + 1;
            LengthZ = MaxPoint.Z - MinPoint.Z + 1;
        }

        public int GetSectionRadius(int d)
        {
            return (int)MathUtils.Pow((Height - MathUtils.Abs(d)) * Radius / Height, 2f);
        }

        public void Ergodic(Action action)
        {
            for (int x = 0; x < LengthX; x++)
            {
                for (int y = 0; y < LengthY; y++)
                {
                    for (int z = 0; z < LengthZ; z++)
                    {
                        Current = new Point3(x + MinPoint.X, y + MinPoint.Y, z + MinPoint.Z);
                        int dx = Current.X - Center.X;
                        int dy = Current.Y - Center.Y;
                        int dz = Current.Z - Center.Z;
                        int sr = 0;
                        int nr = 0;
                        switch (Coord)
                        {
                            case CoordDirection.PX: sr = dy * dy + dz * dz; nr = GetSectionRadius(dx); break;
                            case CoordDirection.NX: sr = dy * dy + dz * dz; nr = GetSectionRadius(dx); break;
                            case CoordDirection.PY: sr = dx * dx + dz * dz; nr = GetSectionRadius(dy); break;
                            case CoordDirection.NY: sr = dx * dx + dz * dz; nr = GetSectionRadius(dy); break;
                            case CoordDirection.PZ: sr = dx * dx + dy * dy; nr = GetSectionRadius(dz); break;
                            case CoordDirection.NZ: sr = dx * dx + dy * dy; nr = GetSectionRadius(dz); break;
                        }
                        if (sr <= nr)
                        {
                            action.Invoke();
                        }
                    }
                }
            }
        }

        public bool Exist(Point3 target)
        {
            bool pass = (target.X >= MinPoint.X && target.Y >= MinPoint.Y && target.Z >= MinPoint.Z);
            bool pass2 = (target.X <= MaxPoint.X && target.Y <= MaxPoint.Y && target.Z <= MaxPoint.Z);
            if (!(pass && pass2)) return false;
            Point3 p = target - Center;
            int sr = 0;
            int nr = 0;
            switch (Coord)
            {
                case CoordDirection.PX: sr = p.Y * p.Y + p.Z * p.Z; nr = GetSectionRadius(p.X); break;
                case CoordDirection.NX: sr = p.Y * p.Y + p.Z * p.Z; nr = GetSectionRadius(p.X); break;
                case CoordDirection.PY: sr = p.X * p.X + p.Z * p.Z; nr = GetSectionRadius(p.Y); break;
                case CoordDirection.NY: sr = p.X * p.X + p.Z * p.Z; nr = GetSectionRadius(p.Y); break;
                case CoordDirection.PZ: sr = p.X * p.X + p.Y * p.Y; nr = GetSectionRadius(p.Z); break;
                case CoordDirection.NZ: sr = p.X * p.X + p.Y * p.Y; nr = GetSectionRadius(p.Z); break;
            }
            return (sr <= nr);
        }
    }
}